/**
 * 外观类提供了一个简的单接口，用于与一个或多个复杂的子系统的逻辑进行交互。它将客户端的请求委派给
 * 子系统内适当的对象，并负责管理它们的生命周期。这样做可以屏蔽客户端对子系统不需要的复杂性。
 */
class Facade {
    protected subsystem1: Subsystem1; // 子系统1对象
    protected subsystem2: Subsystem2; // 子系统2对象

    /**
     * 创建外观实例时，可以选择提供已有的子系统对象，也可以让外观自己创建新的子系统对象。
     */
    constructor(subsystem1?: Subsystem1, subsystem2?: Subsystem2) {
        this.subsystem1 = subsystem1 || new Subsystem1(); // 创建或使用现有的子系统1对象
        this.subsystem2 = subsystem2 || new Subsystem2(); // 创建或使用现有的子系统2对象
    }

    /**
     * 外观类的方法是对子系统复杂功能的简单调用。客户端只能使用子系统的一部分功能。
     */
    public operation(): string {
        let result = '外观初始化子系统:\n';
        result += this.subsystem1.operation1(); // 调用子系统1的操作1
        result += this.subsystem2.operation1(); // 调用子系统2的操作1
        result += '外观命令子系统执行动作:\n';
        result += this.subsystem1.operationN(); // 调用子系统1的操作N
        result += this.subsystem2.operationZ(); // 调用子系统2的操作Z

        return result;
    }
}

/**
 * 子系统可以接受来自外观或客户端的请求。对于子系统而言，外观就是另一个客户端，不是子系统的一部分。
 */
class Subsystem1 {
    public operation1(): string {
        return '子系统1：准备就绪！\n';
    }

    // ...

    public operationN(): string {
        return '子系统1：开始！\n';
    }
}

/**
 * 一些外观可以同时使用多个子系统。
 */
class Subsystem2 {
    public operation1(): string {
        return '子系统2：准备！\n';
    }

    // ...

    public operationZ(): string {
        return '子系统2：开火！';
    }
}
/**
 * 客户端通过外观类与复杂子系统进行交互。当外观管理子系统的生命周期时，
 * 客户端甚至可能不知道子系统的存在。这种方法可以使您保持复杂性的控制。
 */
// @ts-ignore
function clientCode(facade: Facade) {
    // ...

    console.log(facade.operation());

    // ...
}

/**
 * 客户端代码可能已经创建了一些子系统对象。在这种情况下，将这些对象传递给外观，
 * 而不是让外观创建新的实例，可能是值得的。
 */
const subsystem1 = new Subsystem1();
const subsystem2 = new Subsystem2();
const facade = new Facade(subsystem1, subsystem2);
clientCode(facade);
